grpc-go client 打印请求的耗时

我们在调用 http server 或执行 SQL/redis 命令时会打印出这些外部系统调用的耗时,以快速定位问题。随着对 grpc 使用的增多,为 grpc client 增加此功能也是很有必要的,本文章就简单介绍下处理方法。

这里以官方的例子进行说明

  1. grpc.Dial() 中添加中间件 logReqTime
1
2
3
4
5
6
7
func main() {
// Set up a connection to the server.
// 添加 grpc.WithUnaryInterceptor(logReqTime())
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithUnaryInterceptor(logReqTime()))
// conn, err := grpc.Dial(address, grpc.WithInsecure())
// ......
}
  1. logReqTime() 实现如下
1
2
3
4
5
6
7
8
9
func logReqTime() grpc.UnaryClientInterceptor {
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
start := time.Now() // 取得调用前的时间
err := invoker(ctx, method, req, reply, cc, opts...) // 调用 rpc 函数
cost := time.Since(start) // 取得调用函数的耗时
fmt.Printf("method[%s] cost[%v]\n", method, cost) // 打印耗时
return err
}
}

进行上述两步的修改后,每次发送请求都会执行中间件 logReqTime,即可打印出调用耗时

  1. 如果需要打印出调用的 rpc server 地址,可使用 grpc.Peer()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func logReqTime() grpc.UnaryClientInterceptor {
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
start := time.Now()
// 使用 grpc.Peer() 取得调用 rpc 服务的地址
p := peer.Peer{}
if opts == nil {
opts = []grpc.CallOption{grpc.Peer(&p)}
} else {
opts = append(opts, grpc.Peer(&p))
}
err := invoker(ctx, method, req, reply, cc, opts...)
cost := time.Since(start)
fmt.Printf("method[%s] call[%s] cost[%v]\n", method, p.Addr, cost)
return err
}
}

执行结果:

1
method[/helloworld.Greeter/SayHello] call[[::1]:50051] cost[3.072303ms]